#pragma once
#include "socket.hpp"
#include <sys/epoll.h>
#include <string.h>

class EpollServer
{
    static const int maxevents = 64;

public:
    EpollServer(uint16_t port)
        : _port(port), _listensock(std::make_unique<net::TcpSocket>(port))
    {
        InetAddr addr("0", _port);
        _listensock->BuildServerSocket(addr);
        _epfd = epoll_create(1024); // 创建epoll句柄
        if (_epfd < 0)
        {
            Log(FATAL, "%s", strerror(errno));
            exit(-1);
        }
        Log(DEBUG, "epoll fd:%d create success", _epfd);

        struct epoll_event event;
        event.events = EPOLLIN;
        event.data.fd = _listensock->SockFd();
        epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock->SockFd(), &event);
    }

    void Loop()
    {
        while (true)
        {
            int timeout = 1000;
            int n = epoll_wait(_epfd, events, maxevents, timeout);
            if (n == 0)
            {
                // Log(DEBUG,"time out");
            }
            else if (n < 0)
            {
                Log(DEBUG, "%s", strerror(errno));
            }
            else
            {
                Log(DEBUG, "event happen");
                execute(n);
            }
        }
    }

    void execute(int n)
    {
        for (int i = 0; i < n; i++)
        {
            if (events[i].events & EPOLLIN)
            {
                if (events[i].data.fd == _listensock->SockFd())
                {
                    // 收到了连接
                    InetAddr clinetaddr;
                    net::socket_ptr clientsock = _listensock->Accept(&clinetaddr);
                    Log(DEBUG, "have a connection fd:%d %s:%d", clientsock->SockFd(), clinetaddr.ip().c_str(), clinetaddr.port());
                    struct epoll_event event;
                    event.events = EPOLLIN;
                    event.data.fd = clientsock->SockFd();
                    epoll_ctl(_epfd, EPOLL_CTL_ADD, clientsock->SockFd(), &event);
                }
                else
                {
                    // 收到了客户端发来的消息
                    int fd = events[i].data.fd;
                    Log(DEBUG, "got a message from a client fd:%d", fd);
                    char buffer[1024];
                    int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
                    if (n == 0) // 客户端退出了
                    {
                        Log(DEBUG, "client fd:%d quit", fd);
                        epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,nullptr);
                        close(fd);
                    }
                    else if (n > 0)
                    {
                        buffer[n]='\0';
                        std::cout << "client fd:" << fd << " say# " << buffer << std::endl;
                        std::string response("server echo# ");
                        response += buffer;
                        send(fd, response.c_str(), response.size() - 1, 0);
                    }
                    else 
                    {
                        Log(ERROR,"%s",strerror(errno));
                        epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,nullptr);
                        close(fd);
                    }
                }
            }
        }
    }

    ~EpollServer()
    {
        _listensock->Close();
        if (_epfd >= 0)
            ::close(_epfd);
    }

private:
    uint16_t _port;
    std::unique_ptr<net::Socket> _listensock;
    int _epfd;
    struct epoll_event events[maxevents];
};
const int EpollServer::maxevents;